package iamutkarshtiwari.github.io.ananas.editimage.fragment.paint;

import iamutkarshtiwari.github.io.ananas.ResourceTable;
import iamutkarshtiwari.github.io.ananas.editimage.EditImageAbility;
import iamutkarshtiwari.github.io.ananas.editimage.ModuleConfig;
import iamutkarshtiwari.github.io.ananas.editimage.utils.Matrix3;
import iamutkarshtiwari.github.io.ananas.editimage.view.CustomPaintView;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import ohos.agp.components.*;
import ohos.agp.components.element.VectorElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.render.Texture;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;

public class PaintFragment extends ComponentContainer implements Component.ClickedListener, BrushConfigDialog.Properties, EraserConfigDialog.Properties {
    public static final int INDEX = ModuleConfig.INDEX_PAINT;
    public static final String TAG = PaintFragment.class.getName();

    private static final float MAX_PERCENT = 100;
    private static final float MAX_ALPHA = 1;
    private static final float INITIAL_WIDTH = 50;

    private boolean isEraser = false;

    private CustomPaintView customPaintView;
    private DirectionalLayout eraserView;
    private DirectionalLayout brushView;

    private BrushConfigDialog brushConfigDialog;
    private EraserConfigDialog eraserConfigDialog;
//    private Dialog loadingDialog;

    private float brushSize = INITIAL_WIDTH;
    private float eraserSize = INITIAL_WIDTH;
    private float brushAlpha = MAX_ALPHA;
    private Color brushColor = Color.WHITE;

    private CompositeDisposable compositeDisposable = new CompositeDisposable();

    PageSlider pageSlider;
    EditImageAbility editImageAbility;


    /**
     * 构造
     *
     * @param context    Context对象
     * @param pageSlider PageSlider对象
     */
    public PaintFragment(Context context, PageSlider pageSlider) {
        super(context);
        editImageAbility = (EditImageAbility) context;
        this.pageSlider = pageSlider;
        this.customPaintView = editImageAbility.paintView;

        initView();
    }

    private void initView() {
        Component component = LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_fragment_paint_layout, null, false);
        addComponent(component);

        setClickListeners();
        initStroke();
    }

    private void setupOptionsConfig() {
        brushConfigDialog = new BrushConfigDialog(getContext());
        brushConfigDialog.setPropertiesChangeListener(this);

        eraserConfigDialog = new EraserConfigDialog(getContext());
        eraserConfigDialog.setPropertiesChangeListener(this);
    }

    private void setClickListeners() {
        eraserView = (DirectionalLayout) findComponentById(ResourceTable.Id_eraser_btn);
        brushView = (DirectionalLayout) findComponentById(ResourceTable.Id_brush_btn);

        eraserView.setClickedListener(this);
        brushView.setClickedListener(this);
        findComponentById(ResourceTable.Id_back_to_main).setClickedListener(this);
        findComponentById(ResourceTable.Id_settings).setClickedListener(this);
    }

    private void initStroke() {
        customPaintView.setWidth(INITIAL_WIDTH);
        customPaintView.setColor(Color.WHITE);
        customPaintView.setStrokeAlpha(MAX_ALPHA);
        customPaintView.setEraserStrokeWidth(INITIAL_WIDTH);
    }


    /**
     * 显示自定义视图
     */
    public void onShow() {
        editImageAbility.mode = EditImageAbility.MODE_PAINT;
        customPaintView.setVisibility(Component.VISIBLE);
        resetButton();

        setupOptionsConfig();
    }

    /**
     * 返回主视图
     */
    public void backToMain() {
        editImageAbility.mode = EditImageAbility.MODE_NONE;
        pageSlider.setCurrentPage(0, false);
        pageSlider.setVisibility(Component.HIDE);
        customPaintView.reset();
        customPaintView.setVisibility(Component.HIDE);
        initStroke();
        onDestroy();
        editImageAbility.saveOrApply(false);
    }

    @Override
    public void onClick(Component component) {
        int id = component.getId();

        if (id == ResourceTable.Id_back_to_main) {
            backToMain();
        } else if (id == ResourceTable.Id_brush_btn) {
            if (isEraser) {
                toggleButtons();
            }
        } else if (id == ResourceTable.Id_eraser_btn) {
            if (!isEraser) {
                toggleButtons();
            }
        } else if (id == ResourceTable.Id_settings) {
            showDialog();
        }
    }

    private void toggleButtons() {
        isEraser = !isEraser;
        customPaintView.setEraser(isEraser);
        int imageRes = isEraser ? ResourceTable.Graphic_ic_eraser_enabled : ResourceTable.Graphic_ic_eraser_disabled;
        ((Image) eraserView.findComponentById(ResourceTable.Id_eraser_btn_icon)).setImageElement(new VectorElement(getContext(), imageRes));
        int resId = isEraser ? ResourceTable.Graphic_ic_brush_grey_24dp : ResourceTable.Graphic_ic_brush_white_24dp;
        ((Image) brushView.findComponentById(ResourceTable.Id_brush_btn_icon)).setImageElement(new VectorElement(getContext(), resId));
    }

    private void resetButton() {
        customPaintView.setEraser(false);
        isEraser = false;
        int imageRes = ResourceTable.Graphic_ic_eraser_disabled;
        ((Image) eraserView.findComponentById(ResourceTable.Id_eraser_btn_icon)).setImageElement(new VectorElement(getContext(), imageRes));
        int resId = isEraser ? ResourceTable.Graphic_ic_brush_grey_24dp : ResourceTable.Graphic_ic_brush_white_24dp;
        ((Image) brushView.findComponentById(ResourceTable.Id_brush_btn_icon)).setImageElement(new VectorElement(getContext(), resId));


//        ((Image) eraserView.findComponentById(ResourceTable.Id_eraser_btn_icon)).setPixelMap(isEraser ? ResourceTable.Graphic_ic_eraser_enabled : ResourceTable.Graphic_ic_eraser_disabled);
//        ((Image) brushView.findComponentById(ResourceTable.Id_brush_btn_icon)).setPixelMap(isEraser ? ResourceTable.Graphic_ic_brush_grey_24dp : ResourceTable.Graphic_ic_brush_white_24dp);
    }

    private void showDialog() {
//        String tag = dialogFragment.tag();
//
//        // Avoid IllegalStateException "Fragment already added"
//        if (dialogFragment.isAdded()) return;
//        dialogFragment.show(requireFragmentManager(), tag);
        if (isEraser) {
            eraserConfigDialog = new EraserConfigDialog(getContext());
            eraserConfigDialog.setPropertiesChangeListener(this);
            eraserConfigDialog.show();
            updateEraserSize();
        } else {
            brushConfigDialog = new BrushConfigDialog(getContext());
            brushConfigDialog.setPropertiesChangeListener(this);
            brushConfigDialog.show();
            updateBrushParams();
        }
    }

    /**
     * 应用修改
     */
    public void savePaintImage() {
        compositeDisposable.clear();

        Disposable applyPaintDisposable = applyPaint(editImageAbility.getMainBit())
                .flatMap(bitmap -> {
                    if (bitmap == null) {
                        return Single.error(new Throwable("Error occurred while applying paint"));
                    } else {
                        return Single.just(bitmap);
                    }
                })
//                .subscribeOn(Schedulers.computation())
////                .observeOn(Schedulers.mainThread())
////                .doOnSubscribe(subscriber -> loadingDialog.show())
////                .doFinally(() -> loadingDialog.dismiss())
                .subscribe(bitmap -> {
                    customPaintView.reset();
                    editImageAbility.changeMainBitmap(bitmap, true);
                    backToMain();
                }, e -> {
                    // Do nothing on error
                });

        compositeDisposable.add(applyPaintDisposable);
    }

    /**
     * 数据清理
     */
//    @Override
    public void onDestroy() {
        compositeDisposable.dispose();
//        super.onDestroy();
    }

    private Single<PixelMap> applyPaint(PixelMap mainBitmap) {
        return Single.fromCallable(() -> {
            Matrix touchMatrix = editImageAbility.getImageViewMatrix(); // editImageAbility.mainImage.getImageViewMatrix();

//            Bitmap resultBit = Bitmap.createBitmap(mainBitmap).copy(
//                    Bitmap.Config.ARGB_8888, true);
            PixelMap.InitializationOptions opt = new PixelMap.InitializationOptions();
            opt.pixelFormat = PixelFormat.ARGB_8888;
            PixelMap resultBit = PixelMap.create(mainBitmap, opt);
            Canvas canvas = new Canvas(new Texture(resultBit));

//            float[] data = new float[9];
            float[] data = touchMatrix.getData();   //getValues(data);
            Matrix3 cal = new Matrix3(data);
            Matrix3 inverseMatrix = cal.inverseMatrix();
            Matrix matrix = new Matrix(inverseMatrix.getValues());//matrix.setValues(inverseMatrix.getValues())

            handleImage(canvas, matrix);

            return resultBit;
        });
    }

    private void handleImage(Canvas canvas, Matrix matrix) {
//        float[] f = new float[9];
        float[] matrixData = matrix.getData();//getValues(f);

        float dx = matrixData[2];//Matrix.MTRANS_X
        float dy = matrixData[5];//Matrix.MTRANS_Y

        float scale_x = matrixData[0];//Matrix.MSCALE_X
        float scale_y = matrixData[4];//Matrix.MSCALE_Y

        canvas.save();
        canvas.translate(dx, dy);
        canvas.scale(scale_x, scale_y);

        if (customPaintView.getPaintBit() != null) {
            canvas.drawPixelMapHolder(new PixelMapHolder(customPaintView.getPaintBit()), 0, 0, new Paint());//drawBitmap
        }
        canvas.restore();
    }

    @Override
    public void onColorChanged(int colorCode) {
        brushColor = new Color(colorCode);
        updateBrushParams();
    }

    @Override
    public void onOpacityChanged(int opacity) {
        brushAlpha = (opacity / MAX_PERCENT) * MAX_ALPHA;
        updateBrushParams();
    }

    @Override
    public void onBrushSizeChanged(int brushSize) {
        if (isEraser) {
            this.eraserSize = brushSize;
            updateEraserSize();
        } else {
            this.brushSize = brushSize;
            updateBrushParams();
        }
    }

    private void updateBrushParams() {
        customPaintView.setColor(brushColor);
        customPaintView.setWidth(brushSize);
        customPaintView.setStrokeAlpha(brushAlpha);
    }

    private void updateEraserSize() {
        customPaintView.setEraserStrokeWidth(eraserSize);
    }
}
